﻿using System;
using System.Collections.Generic;

using System.Text;

namespace RoughJs.Ast
{
    /// <summary>
    /// 2010-01-5 ----- 2010-01-29
    /// 陈曦 1.0
    /// Microsoft Public License (Ms-PL)
    ///This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.
    ///1. Definitions
    ///The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law.
    ///A "contribution" is the original software, or any additions or changes to the software.
    ///A "contributor" is any person that distributes its contribution under this license.
    ///"Licensed patents" are a contributor's patent claims that read directly on its contribution.
    ///2. Grant of Rights
    ///(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
    ///(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
    ///3. Conditions and Limitations
    ///(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
    ///(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
    ///(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
    ///(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
    ///(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.  
    /// 
    /// 
    /// 脚本或者方法节点
    /// </summary>
    public class ScriptOrFnNode : Node.Scope
    {
        public ScriptOrFnNode(int noteType)
            : base(noteType)
        {
            symbols = new List<Symbol>(4);
            setParent(null);
        }
        public String getSourceName() { return sourceName; }

        /// <summary>
        /// 加入符号
        /// </summary>
        /// <param name="symbol">符号节点</param>
        public void addSymbol(Symbol symbol)
        {
            if (variableNames != null) throw Kit.codeBug();
            if (symbol.declType == Token.LP)
            {
                paramCount++;
            }
            symbols.Add(symbol);
        }

        public int addRegexp(String _string, String flags)
        {
            if (_string == null) Kit.codeBug();
            if (regexps == null) { regexps = new ObjArray(); }
            regexps.add(_string);
            regexps.add(flags);
            return regexps.size() / 2 - 1;
        }

        public int addFunction(FunctionNode fnNode)
        {
            if (fnNode == null) Kit.codeBug();
            if (functions == null) { functions = new ObjArray(); }
            functions.add(fnNode);
            return functions.size() - 1;
        }

        public int getEncodedSourceStart() { return encodedSourceStart; }

        public int getEncodedSourceEnd() { return encodedSourceEnd; }

        public void setEncodedSourceBounds(int start, int end)
        {
            this.encodedSourceStart = start;
            this.encodedSourceEnd = end;
        }

        public int getRegexpCount()
        {
            if (regexps == null) { return 0; }
            return regexps.size() / 2;
        }
        public String getRegexpString(int index)
        {
            return (String)regexps.get(index * 2);
        }

        //public int addRegexp(String string1, String flags)
        //{
        //    if (string1 == null) Kit.codeBug();
        //    if (regexps == null) { regexps = new ObjArray(); }
        //    regexps.add(string1);
        //    regexps.add(flags);
        //    return regexps.size() / 2 - 1;
        //}

        public void setSourceName(String sourceName)
        {
            this.sourceName = sourceName;
        }

        public String getRegexpFlags(int index)
        {
            return (String)regexps.get(index * 2 + 1);
        }

        public String getNextTempName()
        {
            return "$" + tempNumber++;
        }

        public int getBaseLineno() { return this.lineno; }

        public void setBaseLineno(int lineno)
        {
            // One time action
            if (lineno < 0 || this.lineno >= 0) Kit.codeBug();
            this.lineno = lineno;
        }
        public int getEndLineno() { return endLineno; }

        public void setEndLineno(int lineno)
        {
            // One time action
            if (lineno < 0 || endLineno >= 0) Kit.codeBug();
            endLineno = lineno;
        }

        public FunctionNode getFunctionNode(int i)
        {
            return (FunctionNode)functions.get(i);
        }

        public int getFunctionCount()
        {
            if (functions == null) { return 0; }
            return functions.size();
        }

        public int getIndexForNameNode(Node nameNode)
        {
            if (variableNames == null) throw Kit.codeBug();
            Node.Scope node = nameNode.getScope();
            Symbol symbol = node == null ? null
                                         : node.getSymbol(nameNode.getString());
            if (symbol == null)
                return -1;
            return symbol.index;
        }

        public String getParamOrVarName(int index)
        {
            if (variableNames == null) throw Kit.codeBug();
            return variableNames[index];
        }

        public int getParamCount()
        {
            return paramCount;
        }

        public int getParamAndVarCount()
        {
            if (variableNames == null) throw Kit.codeBug();
            return symbols.Count;
        }

        public String[] getParamAndVarNames()
        {
            if (variableNames == null) throw Kit.codeBug();
            return variableNames;
        }

        public bool[] getParamAndVarConst()
        {
            if (variableNames == null) throw Kit.codeBug();
            return isConsts;
        }

        public Object getCompilerData()
        {
            return compilerData;
        }

        public void setCompilerData(Object data)
        {
            if (data == null) throw new ArgumentException();
            // Can only call once
            if (compilerData != null) throw new Exception();
            compilerData = data;
        }

        public void flattenSymbolTable(bool flattenAllTables)
        {
            if (!flattenAllTables)
            {
                List<Symbol> newSymbols = new List<Symbol>();
                if (this.symbolTable != null)
                {
                    // Just replace "symbols" with the symbols in this object's
                    // symbol table. Can't just work from symbolTable map since
                    // we need to retain duplicate parameters.
                    for (int i = 0; i < symbols.Count; i++)
                    {
                        Symbol symbol = symbols[i];
                        if (symbol.containingTable == this)
                        {
                            newSymbols.Add(symbol);
                        }
                    }
                }
                symbols = newSymbols;
            }
            variableNames = new String[symbols.Count];
            isConsts = new bool[symbols.Count];
            for (int i = 0; i < symbols.Count; i++)
            {
                Symbol symbol = symbols[i];
                variableNames[i] = symbol.name;
                isConsts[i] = symbol.declType == Token.CONST;
                symbol.index = i;
            }
        }


        private int encodedSourceStart;
        private int encodedSourceEnd;

        private int endLineno = -1;

        private ObjArray functions;
        private ObjArray regexps;
        private bool[] isConsts;

        private String sourceName;
        private int paramCount = 0;
        private String[] variableNames;
        private IList<Symbol> symbols;

        private Object compilerData;
        private int tempNumber = 0;
    }
}
